package eredis

import (
	"context"
	"encoding/json"
	"errors"
	"git.edaijia-inc.cn/edaijia/ego/elogger"
)

//ListProduct
/*
 * redis list 作为队列的生产方法
 * 参数:   qname 队列名称
 *         payload 消息
 * 返回值: error redis错误或者json错误
 */
func (e *ERedis) ListProduct(qname string, data interface{}) error {
	payload, err := json.Marshal(data)
	if err != nil {
		elogger.Error("eredis ListProduct json error: ", err)
		return err
	}

	_, err = e.Do(nil, "LPUSH", qname, payload)
	if err != nil {
		elogger.Error("eredis ListProduct redis error: ", err)
		return err
	}

	return nil
}

//ListConsume
/*
 * redis list 作为队列的消费方法
 * 参数:   qname 队列名称
 *         data 队列数据结构体或者map 必须传地址
 *         blockSecond 阻塞模式下等待时间,为0时使用非阻塞
 * 返回值: empty 当前队列为空,没有消费到
 *         error redis错误或者json错误
 */
func (e *ERedis) ListConsume(qname string, data interface{}, blockSecond int) (bool, error) {
	var empty bool = true
	var jsonData []byte
	if blockSecond <= 0 {
		payload, err := e.Do(nil, "RPOP", qname)
		if err != nil {
			elogger.Error("eredis ListConsume redis error:", err)
			return empty, err
		}
		if payload != nil {
			empty = false
			jsonData = []byte(payload.(string))
		} else {
			return empty, nil
		}
	} else {
		payload, err := e.Do(nil, "BRPOP", qname, blockSecond)
		if err != nil {
			elogger.Error("eredis ListConsume redis error:", err)
			return empty, err
		}
		if payload != nil {
			empty = false
			jsonDatas := []byte(payload.([]interface{})[1].(string))
			if len(jsonDatas) < 1 {
				// never here
				err = errors.New("redis response error")
				elogger.Error("eredis ListConsume payload format error: ", err)
				return empty, err
			}
			jsonData = jsonDatas
		} else {
			return empty, nil
		}
	}
	if len(jsonData) > 0 {
		elogger.Info("eredis ListConsume get payload:", string(jsonData))
		err := json.Unmarshal(jsonData, data)
		if err != nil {
			elogger.Error("eredis ListConsume json error:", err)
			return empty, err
		}
	} else {
		err := errors.New("payload len < 0")
		elogger.Error("eredis ListConsume payload format error:", err)
		return empty, err
	}
	return empty, nil
}

//SetEx SET方法
func (e *ERedis) SetEx(ctx context.Context, key string, expire int, value interface{}) error {
	_, err := e.Do(ctx, "SETEX", key, expire, value)
	return err
}

//Lock 加锁方法
func (e *ERedis) Lock(ctx context.Context, key string, expire int, value interface{}) bool {
	do, err := e.Do(ctx, "SET", key, value, "EX", expire, "NX")
	if err != nil {
		if err.Error() != "redis: nil" {
			elogger.Error("ERedis,Lock,err="+err.Error(), ",key="+key)
		}
		return false
	}
	if do.(string) == "OK" {
		return true
	}
	return false
}

//UnLock 解锁方法
func (e *ERedis) UnLock(ctx context.Context, key string) bool {
	_, err := e.Do(ctx, "DEL", key)
	if err != nil {
		elogger.Error("ERedisRepo,UnLock,err="+err.Error(), ",key="+key)
		return false
	}
	return true
}

//Del 删除
func (e *ERedis) Del(ctx context.Context, key string) bool {
	_, err := e.Do(ctx, "DEL", key)
	if err != nil {
		elogger.Error("ERedisRepo,Del,err="+err.Error(), ",key="+key)
		return false
	}
	return true
}
func (e *ERedis) Get(ctx context.Context, key string) string {
	do, err := e.Do(ctx, "GET", key)
	if err != nil && err.Error() != "redis: nil" {
		elogger.Error("ERedisRepo,GET,err="+err.Error(), ",key="+key)
	}
	if do == nil || err != nil {
		return ""
	}
	return do.(string)
}
func (e *ERedis) HGet(ctx context.Context, key, field string) string {
	do, err := e.Do(ctx, "HGET", key, field)
	if err != nil && err.Error() != "redis: nil" {
		elogger.Error("ERedisRepo,HGet,err="+err.Error(), ",key="+key, ",filed="+field)
	}
	if do == nil || err != nil {
		return ""
	}
	return do.(string)
}
func (e *ERedis) HSet(ctx context.Context, key, filed string, value interface{}) bool {
	_, err := e.Do(ctx, "HSET", key, filed, value)
	if err != nil {
		elogger.Error("ERedisRepo,HSet,err="+err.Error(), ",key="+key, ",filed="+filed)
		return false
	}
	return true
}
func (e *ERedis) HGetAll(ctx context.Context, key string) interface{} {
	do, err := e.Do(ctx, "HGETALL", key)
	if err != nil {
		elogger.Error("ERedisRepo,HGetAll,err="+err.Error(), ",key="+key)
	}
	if do == nil || err != nil {
		return nil
	}
	return do
}
func (e *ERedis) Expire(ctx context.Context, key string, expire int) bool {
	_, err := e.Do(ctx, "EXPIRE", key, expire)
	if err != nil {
		elogger.Error("ERedisRepo,Expire,err="+err.Error(), ",key="+key)
		return false
	}
	return true
}
func (e *ERedis) ZRem(ctx context.Context, key string, field string) bool {
	_, err := e.Do(ctx, "ZREM", key, field)
	if err != nil {
		elogger.Error("ERedisRepo,ZRem,err="+err.Error(), ",key="+key)
		return false
	}
	return true
}
func (e *ERedis) GeoAdd(ctx context.Context, key string, lng float64, lat float64, value interface{}) bool {
	_, err := e.Do(ctx, "GEOADD", key, lng, lat, value)
	if err != nil {
		elogger.Error("ERedisRepo,GeoAdd,err="+err.Error(), ",key="+key)
		return false
	}
	return true
}
func (e *ERedis) Exists(ctx context.Context, key string) bool {
	do, err := e.Do(ctx, "EXISTS", key)
	if err != nil {
		elogger.Error("ERedisRepo,Exists,err="+err.Error(), ",key="+key)
		return false
	}
	isSuccess := false
	switch do := do.(type) {
	case string:
		if do == "1" {
			isSuccess = true
		}
	case int64:
		if do == 1 {
			isSuccess = true
		}
	case int:
		if do == 1 {
			isSuccess = true
		}
	}
	return isSuccess
}
func (e *ERedis) HsetNx(ctx context.Context, key string, field string, value interface{}) bool {
	do, err := e.Do(ctx, "HSETNX", key, field, value)
	if err != nil {
		elogger.Error("ERedisRepo,HSETNX,err="+err.Error(), ",key="+key)
		return false
	}
	isSuccess := false
	switch do := do.(type) {
	case string:
		if do == "1" {
			isSuccess = true
		}
	case int64:
		if do == 1 {
			isSuccess = true
		}
	case int:
		if do == 1 {
			isSuccess = true
		}
	}
	return isSuccess
}
func (e *ERedis) HExists(ctx context.Context, key, field string) bool {
	do, err := e.Do(ctx, "HEXISTS", key, field)
	if err != nil {
		elogger.Error("ERedisRepo,HExists,err="+err.Error(), ",key="+key)
		return false
	}
	isSuccess := false
	switch do := do.(type) {
	case string:
		if do == "1" {
			isSuccess = true
		}
	case int64:
		if do == 1 {
			isSuccess = true
		}
	case int:
		if do == 1 {
			isSuccess = true
		}
	}
	return isSuccess
}
func (e *ERedis) GeoRadIus(ctx context.Context, key string, lat, lng float64, distance, count int) []interface{} {
	do, err := e.Do(ctx, "GEORADIUS", key, lng, lat, distance, "m", "WITHDIST", "COUNT", count, "asc")
	if err != nil || do == nil {
		if err != nil && err.Error() != "redisRepo: nil" {
			elogger.Error("ERedisRepo,GeoRadIus,err="+err.Error(), ",key="+key)
		}
		return nil
	}
	return do.([]interface{})
}
func (e *ERedis) ZRangeByScore(ctx context.Context, key string, value interface{}, sType string) []interface{} {
	do, err := e.Do(ctx, "ZRANGEBYSCORE", key, value, sType)
	if err != nil || do == nil {
		if err != nil && err.Error() != "redisRepo: nil" {
			elogger.Error("ERedisRepo,ZRangeByScore,err="+err.Error(), ",key="+key)
		}
		return nil
	}
	return do.([]interface{})
}
func (e *ERedis) LRange(ctx context.Context, key string, start int, end int) []interface{} {
	do, err := e.Do(ctx, "LRANGE", key, start, end)
	if err != nil || do == nil {
		if err != nil && err.Error() != "redisRepo: nil" {
			elogger.Error("ERedisRepo,LRange,err="+err.Error(), ",key="+key)
		}
		return nil
	}
	return do.([]interface{})
}
func (e *ERedis) SisMember(ctx context.Context, key string, field string) bool {
	do, err := e.Do(ctx, "SISMEMBER", key, field)
	if err != nil || do == nil {
		if err != nil && err.Error() != "redisRepo: nil" {
			elogger.Error("ERedisRepo,SisMember,err="+err.Error(), ",key="+key)
		}
		return false
	}
	switch do.(type) {
	case int:
		if do.(int) == 1 {
			return true
		}
	case int64:
		if do.(int64) == 1 {
			return true
		}
	}
	return false
}
func (e *ERedis) ZrevRange(ctx context.Context, key string, start int, end int, scores string) []interface{} {
	var do interface{}
	var err error
	if len(scores) > 0 {
		do, err = e.Do(ctx, "ZREVRANGE", key, start, end, scores)
	} else {
		do, err = e.Do(ctx, "ZREVRANGE", key, start, end)
	}
	if err != nil && err.Error() != "redisRepo: nil" {
		elogger.Error("ERedisRepo,ZrevRange,err="+err.Error(), ",key="+key)
		return nil
	}
	return do.([]interface{})
}
func (e *ERedis) ZRange(ctx context.Context, key string, start int, end int, scores string) []interface{} {
	var do interface{}
	var err error
	if len(scores) > 0 {
		do, err = e.Do(ctx, "ZRANGE", key, start, end, scores)
	} else {
		do, err = e.Do(ctx, "ZRANGE", key, start, end)
	}
	if err != nil && err.Error() != "redisRepo: nil" {
		elogger.Error("ERedisRepo,ZRange,err="+err.Error(), ",key="+key)
		return nil
	}
	return do.([]interface{})
}
func (e *ERedis) ZAdd(ctx context.Context, key string, score interface{}, value interface{}) {
	_, err := e.Do(ctx, "ZADD", key, score, value)
	if err != nil && err.Error() != "redisRepo: nil" {
		elogger.Error("ERedisRepo,ZAdd,err="+err.Error(), ",key="+key)
	}
}
func (e *ERedis) Ttl(ctx context.Context, key string) int {
	do, err := e.Do(ctx, "TTL", key)
	if err != nil && err.Error() != "redisRepo: nil" {
		elogger.Error("ERedisRepo,Ttl,err="+err.Error(), ",key="+key)
	}
	switch i := do.(type) {
	case int:
		return i
	case int64:
		return int(i)
	}
	return 0
}
func (e *ERedis) HDel(ctx context.Context, key string, filed string) {
	_, err := e.Do(ctx, "HDEL", key, filed)
	if err != nil && err.Error() != "redisRepo: nil" {
		elogger.Error("ERedisRepo,HDel,err="+err.Error(), ",key="+key)
	}
}
func (e *ERedis) ZrevRank(ctx context.Context, key string, filed string) int {
	do, err := e.Do(ctx, "ZREVRANK", key, filed)
	if err != nil && err.Error() != "redisRepo: nil" {
		elogger.Error("ERedis,ZrevRank,err="+err.Error(), ",key="+key)
	}
	if do == nil {
		return -1
	}
	switch i := do.(type) {
	case int:
		return i
	case int64:
		return int(i)
	}
	return -1
}
func (e *ERedis) ZCard(ctx context.Context, key string) int {
	do, err := e.Do(ctx, "ZCARD", key)
	if err != nil && err.Error() != "redisRepo: nil" {
		elogger.Error("ERedis,ZCard,err="+err.Error(), ",key="+key)
	}
	switch i := do.(type) {
	case int:
		return i
	case int64:
		return int(i)
	}
	return 0
}
func (e *ERedis) HLen(ctx context.Context, key string) int {
	do, err := e.Do(ctx, "HLEN", key)
	if err != nil && err.Error() != "redisRepo: nil" {
		elogger.Error("ERedis,HLen,err="+err.Error(), ",key="+key)
	}
	switch i := do.(type) {
	case int:
		return i
	case int64:
		return int(i)
	}
	return 0
}
func (e *ERedis) SAdd(ctx context.Context, key string, score interface{}, value interface{}) {
	_, err := e.Do(ctx, "SADD", key, score, value)
	if err != nil && err.Error() != "redisRepo: nil" {
		elogger.Error("ERedis,SAdd,err="+err.Error(), ",key="+key)
	}
}
